﻿#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using starLiGHT;

#endregion

#region COPYRIGHT

/*
    Copyright (c) 2008, 2009, 2010 
        Roland Rosenkranz (Glatzemann@email.de)
*/

#endregion

#region LICENSE

/*
    This file is part of starLiGHT.Collision.

    starLiGHT.Collision is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    starLiGHT.Collision is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with starLiGHT.Collision.  If not, see <http://www.gnu.org/licenses/>.

    
    ADDITIONAL (commercial) LICENSES for starLiGHT.Collision are available on request.
*/

#endregion

#region Box2D Copyright
/*
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#endregion

#region Version Stuff
// **************[ starLiGHT.Engine SVN ]**********************
// * $Rev:: 1486                  $:  Revision of last commit *
// * $Author:: glatzemann         $:  Author of last commit   *
// * $Date:: 2010-10-08 15:55:47 #$:  Date of last commit     *
// ************************************************************

// **************[ Box2D-Repository Info ]*********************
// Header-File: http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Collision/Shapes/LoopShape.h
// Revision   : r132
// Change-Date: 2010-09-21
//
// Source-File: http://code.google.com/p/box2d/source/browse/trunk/Box2D/Box2D/Collision/Shapes/LoopShape.cpp
// Revision   : r132
// Change-Date: 2010-09-21
//
// Status     : Finished!
#endregion

namespace starLiGHT.Physic.TwoD
{
    /// <summary>
    /// A loop shape is a free form sequence of line segments that form a circular list.
    /// The loop may cross upon itself, but this is not recommended for smooth collision.
    /// The loop has double sided collision, so you can use inside and outside collision.
    /// Therefore, you may use any winding order.
    /// </summary>
    public class LoopShape : Shape
    {
        public LoopShape()
        {
            m_type = ShapeType.LOOP;
            m_radius = PhysicSettings.PolygonRadius;
            m_vertices = null;
            m_count = 0;
        }

        ~LoopShape()
        {
            m_vertices = null;
            m_count = 0;
        }

        public void Create(Vector2[] vertices, int count)
        {
            System.Diagnostics.Debug.Assert(m_vertices == null && m_count == 0);
            System.Diagnostics.Debug.Assert(count >= 2);
            m_count = count;
            m_vertices = (Vector2[])vertices.Clone();
        }

        public override Shape Clone()
        {
            var clone = new LoopShape();
            clone.m_type = m_type;
            clone.m_radius = m_radius;
            clone.m_vertices = (Vector2[])m_vertices.Clone();
            clone.m_count = m_count;

            return clone;
        }

        public override int GetChildCount()
        {
            return m_count;
        }

        public void GetChildEdge(out EdgeShape edge, int index)
 	    {
            edge = new EdgeShape();

 	        System.Diagnostics.Debug.Assert(2 <= m_count);
 	        System.Diagnostics.Debug.Assert(0 <= index && index < m_count);
 	        edge.m_type = ShapeType.EDGE;
 	        edge.m_radius = m_radius;
 	        edge.m_hasVertex0 = true;
 	        edge.m_hasVertex3 = true;

            int i0 = index - 1 >= 0 ? index - 1 : m_count - 1;
 	        int i1 = index;
 	        int i2 = index + 1 < m_count ? index + 1 : 0;
 	        int i3 = index + 2;
 	        while (i3 >= m_count)
 	        {
 	            i3 -= m_count;
 	        }

            edge.m_vertex0 = m_vertices[i0];
 	        edge.m_vertex1 = m_vertices[i1];
 	        edge.m_vertex2 = m_vertices[i2];
 	        edge.m_vertex3 = m_vertices[i3];
 	    }

        public override bool TestPoint(ref Transform xf, Vector2 p)
        {
            return false;
        }

        // p = p1 + t * d
        // v = v1 + s * e
        // p1 + t * d = v1 + s * e
        // s * e - t * d = p1 - v1
        //

        public override bool RayCast(out RayCastOutput output, ref RayCastInput input, ref Transform xf, int childIndex)
        {
            System.Diagnostics.Debug.Assert(childIndex < m_count);

            EdgeShape edgeShape = new EdgeShape();

            int i1 = childIndex;
            int i2 = childIndex + 1;
            if (i2 == m_count)
            {
                i2 = 0;
            }

            edgeShape.m_vertex1 = m_vertices[i1];
            edgeShape.m_vertex2 = m_vertices[i2];

            return edgeShape.RayCast(out output, ref input, ref xf, 0);
        }

        public override void ComputeAABB(out AABB aabb, ref Transform xf, int childIndex)
        {
            System.Diagnostics.Debug.Assert(childIndex < m_count);

            int i1 = childIndex;
            int i2 = childIndex + 1;
            if (i2 == m_count)
            {
                i2 = 0;
            }

            Vector2 v1 = Math.Mul(xf, m_vertices[i1]);
            Vector2 v2 = Math.Mul(xf, m_vertices[i2]);

            aabb.lowerBound = Vector2.Min(v1, v2);
            aabb.upperBound = Vector2.Max(v1, v2);
        }

        public override void ComputeMass(out MassData massData, float density)
        {
            massData.mass = 0.0f;
            massData.center = Vector2.Zero;
            massData.I = 0.0f;
        }

        public int Count
        {
            get { return m_count; }
        }

        public Vector2 GetVertex(int index)
        {
            System.Diagnostics.Debug.Assert(0 <= index && index < m_count);
            return m_vertices[index];
        }

        public Vector2[] Vertices
        {
            get { return m_vertices; }
        }

        // The vertices. These are not owned/freed by the loop shape.
        Vector2[] m_vertices;
        
        // The vertex count.
        int m_count;
    }
}
